{
s_time_t now;
unsigned long flags;
+
read_lock_irqsave(&xtime_lock, flags);
+
now = stime_irq + get_time_delta();
+
+ /* Ensure that the returned system time is monotonically increasing. */
+ {
+ static s_time_t prev_now = 0;
+ if ( unlikely(now < prev_now) )
+ now = prev_now;
+ prev_now = now;
+ }
+
read_unlock_irqrestore(&xtime_lock, flags);
+
return now;
}
for ( rdtsc_bitshift = 0; cpu_ghz != 0; rdtsc_bitshift++, cpu_ghz >>= 1 )
continue;
- /*
- * We actually adjust cpu_freq to be 0.001% slower than the real
- * frequenecy. This makes time run a little bit slower when interpolating
- * the passage of time between periodic interrupts, so we expect a little
- * jump in time whenever an interrupt comes in (roughly 100ns every 10ms).
- * However, this should avoid us considtently running too fast and jumping
- * _backwards_ on each interrupt, which would be much worse!
- */
- cpu_freq = cpu_freq - (cpu_freq / 100000ULL);
-
scale = 1000000000LL << (32 + rdtsc_bitshift);
scale /= cpu_freq;
st_scale_f = scale & 0xffffffff;
static u32 shadow_time_version;
static struct timeval shadow_tv;
+/*
+ * We use this to ensure that gettimeofday() is monotonically increasing. We
+ * only break this guarantee if the wall clock jumps backwards "a long way".
+ */
+static struct timeval last_seen_tv = {0,0};
+
#ifdef CONFIG_XENO_PRIV
-/* Periodically propagate synchronised time to the RTC and to Xen. */
-static long last_rtc_update, last_xen_update;
+/* Periodically propagate synchronised time base to the RTC and to Xen. */
+static long last_update_to_rtc, last_update_to_xen;
#endif
+/* Periodically take synchronised time base from Xen, if we need it. */
+static long last_update_from_xen;
+
static u64 processed_system_time;
#define HANDLE_USEC_UNDERFLOW(_tv) \
again:
read_lock_irqsave(&xtime_lock, flags);
+
_tv.tv_usec = get_time_delta_usecs();
if ( (lost = (jiffies - wall_jiffies)) != 0 )
_tv.tv_usec += lost * (1000000 / HZ);
_tv.tv_sec = xtime.tv_sec;
_tv.tv_usec += xtime.tv_usec;
+
if ( unlikely(!TIME_VALUES_UP_TO_DATE) )
{
/*
write_unlock_irqrestore(&xtime_lock, flags);
goto again;
}
- read_unlock_irqrestore(&xtime_lock, flags);
HANDLE_USEC_OVERFLOW(_tv);
+ /* Ensure that time-of-day is monotonically increasing. */
+ if ( (_tv.tv_sec < last_seen_tv.tv_sec) ||
+ ((_tv.tv_sec == last_seen_tv.tv_sec) &&
+ (_tv.tv_usec < last_seen_tv.tv_usec)) )
+ _tv = last_seen_tv;
+ last_seen_tv = _tv;
+
+ read_unlock_irqrestore(&xtime_lock, flags);
+
*tv = _tv;
}
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
+ /* Reset all our running time counts. They make no sense now. */
+ last_seen_tv.tv_sec = 0;
+ last_update_from_xen = 0;
+
#ifdef CONFIG_XENO_PRIV
if ( start_info.dom_id == 0 )
{
dom0_op_t op;
- last_rtc_update = last_xen_update = 0;
+ last_update_to_rtc = last_update_to_xen = 0;
op.cmd = DOM0_SETTIME;
op.u.settime.secs = newtv.tv_sec;
op.u.settime.usecs = newtv.tv_usec;
struct pt_regs *regs)
{
s64 delta;
+ long sec_diff;
get_time_values_from_xen();
processed_system_time += NS_PER_TICK;
}
- if ( !independent_wallclock && ((time_status & STA_UNSYNC) != 0) )
+ /*
+ * Take synchronised time from Xen once a minute if we're not
+ * synchronised ourselves, and we haven't chosen to keep an independent
+ * time base.
+ */
+ if ( !independent_wallclock &&
+ ((time_status & STA_UNSYNC) != 0) &&
+ (xtime.tv_sec > (last_update_from_xen + 60)) )
{
/* Adjust shadow timeval for jiffies that haven't updated xtime yet. */
shadow_tv.tv_usec -= (jiffies - wall_jiffies) * (1000000/HZ);
HANDLE_USEC_UNDERFLOW(shadow_tv);
+ /*
+ * Reset our running time counts if they are invalidated by a warp
+ * backwards of more than 500ms.
+ */
+ sec_diff = xtime.tv_sec - shadow_tv.tv_sec;
+ if ( unlikely(abs(sec_diff) > 1) ||
+ unlikely(((sec_diff * 1000000) +
+ xtime.tv_usec - shadow_tv.tv_usec) > 500000) )
+ {
+ last_update_to_rtc = last_update_to_xen = 0;
+ last_seen_tv.tv_sec = 0;
+ }
+
/* Update our unsynchronised xtime appropriately. */
xtime = shadow_tv;
+
+ last_update_from_xen = xtime.tv_sec;
}
#ifdef CONFIG_XENO_PRIV
if ( (start_info.dom_id == 0) && ((time_status & STA_UNSYNC) == 0) )
{
/* Send synchronised time to Xen approximately every minute. */
- if ( xtime.tv_sec > (last_xen_update + 60) )
+ if ( xtime.tv_sec > (last_update_to_xen + 60) )
{
dom0_op_t op;
struct timeval tv = xtime;
op.u.settime.system_time = shadow_system_time;
HYPERVISOR_dom0_op(&op);
- last_xen_update = xtime.tv_sec;
+ last_update_to_xen = xtime.tv_sec;
}
/*
* clock accordingly every ~11 minutes. Set_rtc_mmss() has to be called
* as close as possible to 500 ms before the new second starts.
*/
- if ( (xtime.tv_sec > (last_rtc_update + 660)) &&
+ if ( (xtime.tv_sec > (last_update_to_rtc + 660)) &&
(xtime.tv_usec >= (500000 - ((unsigned) tick) / 2)) &&
(xtime.tv_usec <= (500000 + ((unsigned) tick) / 2)) )
{
if ( set_rtc_mmss(xtime.tv_sec) == 0 )
- last_rtc_update = xtime.tv_sec;
+ last_update_to_rtc = xtime.tv_sec;
else
- last_rtc_update = xtime.tv_sec - 600;
+ last_update_to_rtc = xtime.tv_sec - 600;
}
}
#endif